package gui;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;

import java.util.*;

import ptolemy.kernel.*;
import ptolemy.vergil.actor.*;

import util.Line;
import MoC.*;
import db.*;
import FlowGraph.*;

//////////////////////////////////////////////////////////////////////////
//// VerifierFrame
/**

@author Ivan Jeukens
@version v 0.1 05/02/2002
*/
public class VerifierFrame extends JFrame {

    public VerifierFrame() {
        super();
        JPanel main = new JPanel();
        main.setLayout(new BorderLayout());

        _top = new JPanel();
        _top.setLayout(new BorderLayout());

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel,
            BoxLayout.X_AXIS));

        /*
        JButton button = new JButton("Locate");
        button.setToolTipText("View error location");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _locateAction();
	    }
        });
        buttonPanel.add(button);*/

        JButton button = new JButton("View Results");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _displayResultsFrame();
	    }
        });
        buttonPanel.add(button);

        // So para fazer testes.......................
        /*
        button = new JButton("View Code");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _displayCode();
	    }
        });
        buttonPanel.add(button); */

        // Produz o codigo dos atores
        /* button = new JButton("Generate Code");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _generateCode();
	    }
        });
        buttonPanel.add(button); */
        //..........................................

        String [] sort = { "Actor", "Phase", "Status", "MoC" };
        final JComboBox sortBox = new JComboBox(sort);
        sortBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String s = (String) sortBox.getSelectedItem();
                if(s.equals(_currentSortSelection)) return;

                _currentSortSelection = s;
                _sortTable();
            }
        });
        buttonPanel.add(sortBox);

        String [] phases = { "All", "Preprocess", "MOC Validatoin",
            "SDF Validation", "SR Validation" };
        final JComboBox phasesBox = new JComboBox(phases);
        phasesBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String s = (String) phasesBox.getSelectedItem();
                if(s.equals(_lastSelected)) return;

                _messagesTableModel.maskPhase(s);
                _lastSelected = s;
            }

            private String _lastSelected = "";
        });
        buttonPanel.add(phasesBox);

        /*
        button = new JButton("View Code");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _displayCode();
	    }
        });
        buttonPanel.add(button); */

        // Produz o codigo dos atores
        /*button = new JButton("Generate Code");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                _generateCode();
	    }
        });
        buttonPanel.add(button);
*/
        _top.add(buttonPanel, BorderLayout.CENTER);

        _messagesTableModel = new MessagesTableModel();
        _messagesTableSorter = new TableSorter(_messagesTableModel);
        _messagesTable = new JTable(_messagesTableSorter);
	    _messagesTable.getTableHeader().setReorderingAllowed(true);
        _messagesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // O renderer para a coluna de status
        TableColumn col = _messagesTable.getColumnModel().getColumn(0);
        col.setCellRenderer(new ActorColumnRenderer());
        
        col = _messagesTable.getColumnModel().getColumn(1);
        col.setCellRenderer(new StatusColumnRenderer());

        col = _messagesTable.getColumnModel().getColumn(2);
        col.setCellRenderer(new PhaseColumnRenderer());

        col = _messagesTable.getColumnModel().getColumn(3);
        col.setCellRenderer(new TextColumnRenderer());

        _currentSortSelection = new String("phase");

        _messagesTable.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent e) {
                if(e.getClickCount() == 2) {
                    Point p = e.getPoint();
                    int row = _messagesTable.rowAtPoint(p);
                    _locateAction(row);
                }
                else
                if(e.getClickCount() == 1) {
                    Point p = e.getPoint();
                    int row = _messagesTable.rowAtPoint(p);
                    if(row == _previousRow) {
                        _messagesTable.clearSelection();
                        _previousRow = -1;
                        _resetLocateAction();
                    }
                    else {
                        _previousRow = row;
                    }
                }
            }

            public void mousePressed(MouseEvent e) { } 
            public void mouseReleased(MouseEvent e) { }
            public void mouseEntered(MouseEvent e) { }
            public void mouseExited(MouseEvent e) { }

            private int _previousRow = -1;
        });

        JScrollPane sc = new JScrollPane(_messagesTable);
        main.add(sc, BorderLayout.CENTER);

        main.add(_top, BorderLayout.NORTH);
        getContentPane().add(main);

        setTitle("Analysis Messages");
    }

    public static final Color BackgroundColor = new Color(0xe5e5e5);

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    /*
    public void dispose() {
        super.dispose();
        _resetLocateAction();
    }
    
    public void hide() {
        super.hide();
        _resetLocateAction();
    }*/

    // Nesse momento, o VerifierTableau esta sendo criado. Entao,
    // a effigy ja tem os resultados.
    public void initialize(VerifierEffigy effigy) {
        _effigy = effigy;
        //_parent = parent;

        String [] mnames = { "All", "SDF", "SR", "PN", "CS", "Independent"};
        final JComboBox mocBox = new JComboBox(mnames);
        mocBox.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) {
                String s = (String) mocBox.getSelectedItem();
                if(s.equals(_lastSelected)) return;
                _messagesTableModel.maskMoC(s);
                _lastSelected = s;
            }
            private String _lastSelected = "";
        });
        _top.add(mocBox, BorderLayout.EAST);

        // Cria a tabela com as mensagens.
        Iterator ite = _effigy.preprocessMessagesIterator();
        while(ite != null && ite.hasNext()) {
            Message m = (Message) ite.next();
            _messagesTableModel.addMessage(m);
        }

        ite = _effigy.commomRestrictionsMessagesIterator();
        while(ite != null && ite.hasNext()) {
            Message m = (Message) ite.next();
            _messagesTableModel.addMessage(m);
        }

        ite = _effigy.sdfValidationMessagesIterator();
        while(ite != null && ite.hasNext()) {
            Message m = (Message) ite.next();
            _messagesTableModel.addMessage(m);
        }
 
        ite = _effigy.srValidationMessagesIterator();
        while(ite != null && ite.hasNext()) {
            Message m = (Message) ite.next();
            _messagesTableModel.addMessage(m);
        }

        _messagesTableModel.createIndex();
        _messagesTableModel.fireTableDataChanged();

        _lastMessageLocation = null;
    }

    /* Seleciona um novo ator ou especificacao para mostrar as mensagens
    de erro */
    public void displayInfo(dbInfo info) {
/*        _currentInfo = info;
        String moc = (String) _mocBox.getSelectedItem();

        Messages m = info.getMessages(moc);
        _messagesTableModel.setMessages(m);
        
        // se for um ator, entao cria o codebrowser
        if(info instanceof AtomicActorInfo) {
            if(_codeBrowser != null) {
                _codeBrowser.dispose();
            }
            _codeBrowser = new CodeBrowser((AtomicActorInfo) _currentInfo);
        }
        else {
            _codeBrowser = null;
        }*/
    }

    public void setCompositeEntity(CompositeEntity actor) {
        _currentComposite = actor;
    }
    
    ///////////////////////////////////////////////////////////////////
    ////                           private methods                 ////

    private void _displayResultsFrame() {
        _resultsFrame = new ResultsFrame(_effigy.getInfo());
        _resultsFrame.show();
    }

    private void _locateAction(int row) {
        _resetLocateAction();

        Message m = _messagesTableModel.getMessageAt(row);

        String text = m.getText();
        if(text != null) {
            JFrame frame = new JFrame("Message Text");
            frame.setSize(400, 300);

            JTextArea ta = new JTextArea();
            ta.setText(text);

            frame.getContentPane().add(new JScrollPane(ta));
            frame.show();
        }
        
        MessageLocation loc = m.getLocation();
        if(loc == null) return;

        switch(loc.getType()) {

            // Erro sobre uma instancia especifica
            case MessageLocation.ACTOR_INSTANCE: {
                ActorInstanceMessageLocation inst = 
                    (ActorInstanceMessageLocation) loc;

                Entity e = inst.getActor();
                ActorGraphTableau t = _effigy.getActorTableau(e);
                ActorGraphFrame f = (ActorGraphFrame) t.getFrame();
                //f.highLightActor(e);
                f.repaint();
            } break;
            
            // Um erro sobre o codigo de um ator atomico. Ilumina instancias
            // relacionadas.
            case MessageLocation.ACTOR: {
                LinkedList l = new LinkedList();
                ActorMessageLocation mloc = (ActorMessageLocation) loc;
                Iterator ite = mloc.actorInstancesIterator();
                while(ite.hasNext()) {
                    Entity e = (Entity) ite.next();
                    ActorGraphTableau t = _effigy.getActorTableau(e);
                    ActorGraphFrame f = (ActorGraphFrame) t.getFrame();
                    //f.highLightActor(e);
                    l.add(f);
                }

                for(int i = 0;i < l.size();i++) {
                    ActorGraphFrame f = (ActorGraphFrame) l.get(i);
                    f.repaint();
                }
            } break;
            
            case MessageLocation.CLASS_SOURCE: {
                ClassMessageLocation mloc = (ClassMessageLocation) loc;

                CodeBrowser browser = new CodeBrowser(mloc.getClassInfo());
                Iterator ite = mloc.linesIterator();
                while(ite.hasNext()) {
                    Line line = (Line) ite.next();

                    FlowGraphNode node = line.getFlowGraphNode();
                    FlowGraph fg = node.getContainer();
                    ClassData cinfo = fg.getClassInfo();

                    browser.setLineForeground(cinfo, line, Color.red);
                }
                browser.show();
            } break;

            case MessageLocation.COMPOSITE: {

                
            } break;
        }
        
        _lastMessageLocation = loc;
    }

    private void _locateAction() {
        int row = _messagesTable.getSelectedRow();
        if(row == -1) return;

        _locateAction(row);
    }
    
    // Desfaz o que o location action fez.
    private void _resetLocateAction() {
        if(_lastMessageLocation == null) return;

        switch(_lastMessageLocation.getType()) {

            case MessageLocation.ACTOR_INSTANCE: {
                ActorInstanceMessageLocation loc = (ActorInstanceMessageLocation)
                    _lastMessageLocation;
                Entity e = loc.getActor();
                ActorGraphTableau t = _effigy.getActorTableau(e);
                ActorGraphFrame f = (ActorGraphFrame) t.getFrame();
                
                //f.deHighLightActor(e);
                //f.repaint();
            } break;

            case MessageLocation.ACTOR: {
                ActorMessageLocation mloc = (ActorMessageLocation)
                    _lastMessageLocation;
                LinkedList l = new LinkedList();
                Iterator ite = mloc.actorInstancesIterator();
                while(ite.hasNext()) {
                    Entity e = (Entity) ite.next();
                    ActorGraphTableau t = _effigy.getActorTableau(e);
                    ActorGraphFrame f = (ActorGraphFrame) t.getFrame();

                    //f.deHighLightActor(e);
                    l.add(f);
                }

                for(int i = 0;i < l.size();i++) {
                    ActorGraphFrame f = (ActorGraphFrame) l.get(i);
                    f.repaint();
                }
            } break;
            
            case MessageLocation.CLASS_SOURCE: {

            } break;
            
            case MessageLocation.COMPOSITE: {

            } break;
        }
    }

    // So pra fazer teste ................................
    private void _displayCode() {
        /*
        if(_currentInfo instanceof AtomicActorInfo) {
            if(_codeBrowser != null) {
                _codeBrowser.dispose();
            }
            _codeBrowser = new CodeBrowser((AtomicActorInfo) _currentInfo);
        }
        else {
            _codeBrowser = null;
        }
        if(_codeBrowser == null) return;
        _codeBrowser.show();*/
    }

    private void _generateCode() {
        /*
        _currentInfo = _effigy.getInfo();
        if(_currentInfo instanceof CompositeActorInfo) {
            CompositeActorInfo ce = (CompositeActorInfo) _currentInfo;
            Iterator ite = ce.atomicActorsIterator();
            while(ite.hasNext()) {
                AtomicActorInfo info = (AtomicActorInfo) ite.next();
                Iterator ite2 = info.classesIterator();
                while(ite2.hasNext()) {
                    ClassData cinfo = (ClassData) ite2.next();
                    if(cinfo.getName().equals("ptolemy.actor.TypedAtomicActor")) break;
                    _generateClassCode(cinfo);
                }
            }
        }
        else
        if(_currentInfo instanceof AtomicActorInfo) {
            Iterator ite = ((AtomicActorInfo)_currentInfo).classesIterator();
            while(ite.hasNext()) {
                ClassData cinfo = (ClassData) ite.next();
                if(cinfo.getName().equals("ptolemy.actor.TypedAtomicActor")) break;

                _generateClassCode(cinfo);
            }
        }*/
        
    }
    
    private void _generateClassCode(ClassData cinfo) {
        return;
        /*
        String text = cinfo.getCodeText();
        URL url = cinfo.getURL();
        StringTokenizer st = new StringTokenizer(url.getFile(), "/");
        String tok = null;

        while(st.hasMoreTokens()) {
            tok = st.nextToken();
        }

        Runtime run = Runtime.getRuntime();
        try {
            System.out.println("## GENERATING " + tok);
            File f = new File("/home/ivan/ta/" + tok);
            FileOutputStream fo = new FileOutputStream(f);
            PrintStream ps = new PrintStream(fo);
            ps.print(text);
            
            System.out.println("## COMPILING " + tok);
            Process p = run.exec("javac /home/ivan/ta/" + tok);
            try {
                p.waitFor();
            }
            catch(Exception ex) { System.out.println(ex); }
            InputStream er = p.getErrorStream();
            int av = er.available();
            byte [] b = new byte[av];
            er.read(b);
            System.out.write(b);
            
        }
        catch(IOException ex) {
            System.out.println(ex);
        }
        System.out.println("-- COMPILATION DONE --");
        */
    }
    
    // ................................................................
    
    private void _sortTable() {
        int typec;
	for(typec = 0;typec < _messagesTable.getColumnCount();typec++) {
	    String cname = _messagesTable.getColumnName(typec);
	    if(cname.equals(_currentSortSelection)) break;
	}
	if(typec < _messagesTable.getColumnCount()) {
	    _messagesTableSorter.sortByColumn(typec);
	}
    }
   
    ///////////////////////////////////////////////////////////////////
    ////                         private variables                 ////

    private JPanel _top;
    //private JComboBox _mocBox;
    private JTable _messagesTable;
    private MessagesTableModel _messagesTableModel;
    private CodeBrowser _codeBrowser = null;

    private dbInfo _currentInfo;

    // Usado para voltar a cor dos atores ao normal.
    private MessageLocation _lastMessageLocation;
 
    private String _currentSortSelection;
    private TableSorter _messagesTableSorter;

    //private VerifierFrame _parent;
    private VerifierEffigy _effigy;

    // O composite sendo analisado. Usado no locate.
    private CompositeEntity _currentComposite;
    private ResultsFrame _resultsFrame;
    
    ///////////////////////////////////////////////////////////////////
    ////                         inner classes                     ////
    
    class ActorColumnRenderer implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, 
                boolean isSelected, boolean hasFocus, int row, int col) {
            if(col != 0) return null;

            String s = (String) value;
            JLabel label = new JLabel(s);
            label.setOpaque(true);

            label.setForeground(Color.black);

            if(isSelected) {
                label.setBackground(new Color(204, 204, 255));
            }
            else {
                label.setBackground(Color.white);
            }
 
            Font f = label.getFont();
            label.setFont(new Font(f.getName(), 0, 12));

            return label;
        }
    }

    class StatusColumnRenderer implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, 
                boolean isSelected, boolean hasFocus, int row, int col) {
            if(col != 1) return null;

            String s = (String) value;
            JLabel label = new JLabel(s);
            label.setOpaque(true);
            
            if(s.equals("Warning")) {
                label.setForeground(Color.orange);
            }
            else
            if(s.equals("Error")) {
                label.setForeground(Color.red);
            }
            else {
                label.setForeground(Color.green);
            }

            if(isSelected) {
                label.setBackground(new Color(204, 204, 255));
            }
            else {
                label.setBackground(Color.white);
            }
 
            Font f = label.getFont();
            label.setFont(new Font(f.getName(), 0, 12));

            return label;
        }
    }
    
    class PhaseColumnRenderer implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, 
                boolean isSelected, boolean hasFocus, int row, int col) {
            if(col != 2) return null;

            String s = (String) value;
            JLabel label = new JLabel(s);
            label.setOpaque(true);
            
            label.setForeground(Color.black);

            if(isSelected) {
                label.setBackground(new Color(204, 204, 255));
            }
            else {
                label.setBackground(Color.white);
            }
 
            Font f = label.getFont();
            label.setFont(new Font(f.getName(), 0, 12));

            return label;
        }
    }

    class TextColumnRenderer implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, 
                boolean isSelected, boolean hasFocus, int row, int col) {
            if(col != 3) return null;

            String s = (String) value;
            JLabel label = new JLabel(s);
            label.setOpaque(true);

            label.setForeground(Color.blue);

            if(isSelected) {
                label.setBackground(new Color(204, 204, 255));
            }
            else {
                label.setBackground(Color.white);
            }

            Font f = label.getFont();
            label.setFont(new Font(f.getName(), 0, 14));

            return label;
        }
    }
}
